Skip to content

Feat: Add version change indicators for Dag and bundle versions in Grid view#53216

Open
choo121600 wants to merge 6 commits intoapache:mainfrom
choo121600:feature/version-indicator
Open

Feat: Add version change indicators for Dag and bundle versions in Grid view#53216
choo121600 wants to merge 6 commits intoapache:mainfrom
choo121600:feature/version-indicator

Conversation

@choo121600
Copy link
Member

@choo121600 choo121600 commented Jul 12, 2025

Summary

Adds visual indicators in the Grid view to help users identify Dag version changes and detect mixed-version TaskInstances within a single DagRun.

Problem

  • After updating a Dag file, it's difficult to know from which DagRun the new version is applied.
  • Some TaskInstances within the same DagRun may use different Dag versions, but this is not visible in the UI.

Solution

This PR introduces visual cues in the Grid view to address these pain points:

  • Dag Version Indicator: Vertical/horizontal orange line with tooltip showing version number
  • Bundle Version Indicator: Git commit icon with tooltip showing bundle version
  • Toggle Options: Users can choose to show None, Dag Version Indicator only, Bundle Version Indicator only, or All indicators

Change

Backend

  • Added bundle_version and dag_version_number fields to GridRunsResponse
  • Modified grid query to JOIN with DagVersion table for efficient single-query data fetch
  • Added dag_version_number to LightGridTaskInstanceSummary for mixed version detection

Frontend

  • New VersionIndicator.tsx component(BundleVersionIndicator, DagVersionIndicator)
  • New useGridRunsWithVersionFlags hook to calculate version change flags
  • Updated Bar.tsx, Grid.tsx, TaskInstancesColumn.tsx to display indicators
  • Added version indicator toggle in PanelButtons.tsx

Screenshots

Version Change

LocalDagBundle

image

Dag Version Indicator Tooltip(vertical)
image

Dag Version Indicator Tooltip(horizontal)
image

GitDagBundle

image

Dag Version Indicator Tooltip
image

Bundle Version Indicator Tooltip
image

Dark Mode

image image

Toggle Option(with Legend)

Users can choose 'Show All', 'Show Dag Version', 'Show Bundle Version', 'Hide All'

image

Show All

image

Show Bundle Version

image

Show Dag Version

image

Hide All

image

Indicator Scenarios

Scenario 1: Normal

  • All tasks run with the same version
  • No indicator (default state)
image

Scenario 2: Version Change

  • Entire run with new version
  • Left indicator + version number tooltip
image image

Scenario 3: Mixed Version

  • Multiple versions within single run
  • Left, Row indicator + version number tooltip
image image image

Scenario 4: Bundle Version & DagVersion Change

image image image

Scenario 5: Only Bundle Change (Dynamic Dag)

image image

closes: #52286


^ Add meaningful description above
Read the Pull Request Guidelines for more information.
In case of fundamental code changes, an Airflow Improvement Proposal (AIP) is needed.
In case of a new dependency, check compliance with the ASF 3rd Party License Policy.
In case of backwards incompatible changes please leave a note in a newsfragment file, named {pr_number}.significant.rst or {issue_number}.significant.rst, in airflow-core/newsfragments.

@boring-cyborg boring-cyborg bot added area:API Airflow's REST/HTTP API area:UI Related to UI/UX. For Frontend Developers. labels Jul 12, 2025
@choo121600 choo121600 force-pushed the feature/version-indicator branch 2 times, most recently from 09ecc2b to bd021e8 Compare July 12, 2025 07:04
Copy link
Contributor

@bugraoz93 bugraoz93 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the PR! I think this is bringing back the deprecated and removed monolith endpoint with its methods. I think we should integrate the fix into only new structure
cc: @dstandish @pierrejeambrun

@choo121600
Copy link
Member Author

@bugraoz93 Thanks for your quick feedback! I saw something strange while fixing the conflict,
So I started checking the main branch — your comment helped me confirm it.

I think my endpoints follow the old style. I’ll change them to use the new structure.

@bugraoz93
Copy link
Contributor

@bugraoz93 Thanks for your quick feedback! I saw something strange while fixing the conflict,
So I started checking the main branch — your comment helped me confirm it.

I think my endpoints follow the old style. I’ll change them to use the new structure.

Amazing, thanks a lot!

@choo121600
Copy link
Member Author

choo121600 commented Jul 13, 2025

I’ve updated the tests and removed the old structure,
but I'm testing whether the feature I added works as before🥲
After verifying the tests, I will leave a comment!

@choo121600
Copy link
Member Author

choo121600 commented Jul 13, 2025

I’ve tested the scenarios I had in mind, and everything looks good so far 🙌
Reviews are welcome from this point.

@choo121600 choo121600 requested a review from bugraoz93 July 13, 2025 09:10
Copy link
Contributor

@bugraoz93 bugraoz93 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the changes! I believe this PR still contains old deprecated code :)

Copy link
Member

@jason810496 jason810496 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice! Thanks for the PR!

@choo121600
Copy link
Member Author

I thought I deleted the old version, but it still there.
Right now, my new code and the old APIs are mixed together, and it looks like the old version is included when I commit 🤔
This might be a problem with my local setup, so I will check and fix it this week.

@ephraimbuddy
Copy link
Contributor

If we want to visualize version change, in my opinion, we should do it for bundle version and not dag version that changes everytime especially for dynamic dags cc @jedcunningham

@bbovenzi
Copy link
Contributor

If we want to visualize version change, in my opinion, we should do it for bundle version and not dag version that changes everytime especially for dynamic dags cc @jedcunningham

In that case, we might need to use an icon and then show the bundle version in a tooltip. Maybe something like <FiGitCommit />

@pierrejeambrun
Copy link
Member

pierrejeambrun commented Jul 16, 2025

If we want to visualize version change, in my opinion, we should do it for bundle version and not dag version that changes everytime especially for dynamic dags cc @jedcunningham

Maybe we need both with different colors, dag version change (to task level) + bundle version change (dag run level only).

If we were to keep only one, I would be in favor of keeping the DagVersion because it is consistant with the Graph(Graph is showing structures of specific dag versions), And because I think source code is less important than what was actually executed.

Copy link
Member

@pierrejeambrun pierrejeambrun left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the code looks very complicated for what we are trying to achieve. (And also there are some unused stuff I believe from the legacy grid)

The backend need to serialize the dag_run.versions in the GridRunsResponse, same for tasks.

And in the UI, we just need a simple logic to check if dag_run.version of Nth run is equal to dag_run.version of (N-1)th run.

(Same logic goes for tasks, and yes if DagRun.dag_versions.lenght === 1 no need to go try the task level logic)

Maybe I missed something though.

@pierrejeambrun
Copy link
Member

In that case, we might need to use an icon and then show the bundle version in a tooltip. Maybe something like

I'm afraid that we can potentially have as many tooltips as TI in the grid. Which would most likely bring back tooltip performance issue we observed in the past.

Copy link
Contributor

@bbovenzi bbovenzi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should add a legend to make it easier for users to learn dag versions vs bundle version changes.

@pierrejeambrun pierrejeambrun added the type:new-feature Changelog: New Features label Nov 4, 2025
@choo121600
Copy link
Member Author

choo121600 commented Nov 6, 2025

@bbovenzi I’ve been thinking about the legend, and currently, the horizontal indicator for Dag version changes and the indicator for bundle version changes use the same icon.
So, distinguishing them by icon alone seems difficult. Instead, I modified the horizontal Dag version change indicator to use a consistent style with the vertical one(a combination of a line and a circle.)

Here’s an example of what it looks like. What do you think?

image image

@choo121600 choo121600 requested a review from bbovenzi November 14, 2025 06:45
@choo121600
Copy link
Member Author

@bbovenzi I’ve been thinking about the legend, and currently, the horizontal indicator for Dag version changes and the indicator for bundle version changes use the same icon. So, distinguishing them by icon alone seems difficult. Instead, I modified the horizontal Dag version change indicator to use a consistent style with the vertical one(a combination of a line and a circle.)

Here’s an example of what it looks like. What do you think?

@bbovenzi @pierrejeambrun This part hasn’t been implemented yet. I’d like to hear your ideas regarding the legend.

@choo121600 choo121600 changed the title Feat: Visualize DAG version changes and mixed versions in Grid view Feat: Add version change indicators for Dag and bundle versions in Grid view Nov 14, 2025
Copy link
Member

@pierrejeambrun pierrejeambrun left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice, looking better and better.

A few suggestions to try to make things simpler and improve UX.

Copy link
Member

@pierrejeambrun pierrejeambrun left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Feel free to mark addressed comments as resolved.

Let me know when this needs another round of review.

@choo121600
Copy link
Member Author

Except for this part #53216 (comment)
I’ve marked the addressed comments as resolved and updated all the screenshots.
@pierrejeambrun Could you review it once more?

@bbovenzi
Copy link
Contributor

bbovenzi commented Jan 8, 2026

We'll need to rebase this after virtualizing the grid's vertical scroll.

@choo121600 choo121600 force-pushed the feature/version-indicator branch from fad0cf6 to f48e7ec Compare January 10, 2026 06:13
@guan404ming
Copy link
Member

Hi, this feature looks really cool. Could you please help resolve the conflicts? Thanks!

@choo121600
Copy link
Member Author

Hi, this feature looks really cool. Could you please help resolve the conflicts? Thanks!

Oops, I missed the notification earlier 😅
I've resolved the conflicts now. Thanks for pointing it out!

Copy link
Member

@guan404ming guan404ming left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Look nice, just left some comments. Thanks!

@choo121600 choo121600 force-pushed the feature/version-indicator branch from c600518 to fdfccb9 Compare February 7, 2026 19:22
Copy link
Member

@guan404ming guan404ming left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

UI wise looks nice thanks!
Left one nit.

Copy link
Member

@pierrejeambrun pierrejeambrun left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice, we're getting closer! Thanks for your continuous effort and being patient, that's a complex feature and that's why there's a bunch of back and forth.

There are a lot of useMemo, I think those are not needed anymore with react-compiler

run_after: datetime
state: DagRunState | None
run_type: DagRunType
bundle_version: str | None = None
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is bundle_version used?

Comment on lines +277 to +287
# get the highest dag_version_number from TIs for each run
latest_ti_version = (
select(
TaskInstance.run_id,
func.max(DagVersion.version_number).label("version_number"),
)
.join(DagVersion, TaskInstance.dag_version_id == DagVersion.id)
.where(TaskInstance.dag_id == dag_id)
.group_by(TaskInstance.run_id)
.subquery()
)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't need to go through all that trouble to only retrieve the 'last' version. Just return the DagRun.dag_versions attribute.

Also this will be consistent for other contributor. People will get confused as to why a DagRun has dag_versions as a list in the plublic interface, but on the grid endpoint here it's only dag_version and not a list anymore.

I find this confusing and it adds a lot of unecessary application code.

Comment on lines +58 to +70
const taskInstances = useMemo(
() => gridTISummaries?.task_instances ?? [],
[gridTISummaries?.task_instances],
);
const taskInstanceMap = useMemo(() => {
const map = new Map<string, LightGridTaskInstanceSummary>();

for (const ti of taskInstances) {
map.set(ti.task_id, ti);
}

return map;
}, [taskInstances]);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought react compiler would memo this for us.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Correct. Let's remove them.

}

return gridRuns.map((run, index) => {
const prevRun = gridRuns[index + 1];
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
const prevRun = gridRuns[index + 1];
const nextRun = gridRuns[index + 1];

Comment on lines +23 to +24
BUNDLE = "bundle",
DAG = "dag",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit:

Suggested change
BUNDLE = "bundle",
DAG = "dag",
BUNDLE_VERSION = "bundle",
DAG_VERSION = "dag",

Comment on lines +118 to +134
let hasVersionChangeFlag = false;

if (
hasMixedVersions &&
(showVersionIndicatorMode === VersionIndicatorDisplayOptions.DAG ||
showVersionIndicatorMode === VersionIndicatorDisplayOptions.ALL) &&
idx > 0
) {
const prevVirtualItem = itemsToRender[idx - 1];
const prevNode = prevVirtualItem ? nodes[prevVirtualItem.index] : undefined;
const prevTaskInstance = prevNode ? taskInstanceMap.get(prevNode.id) : undefined;

hasVersionChangeFlag = Boolean(
prevTaskInstance && prevTaskInstance.dag_version_number !== taskInstance.dag_version_number,
);
}

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why aren't we checking for BundleVersion change too ?

DagVersion could be the same (serialized dag is identical) but the bundle version changed (version of the file in the code)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we only use this in the grid view then we should move it to layouts/Details/Grid instead. components are for general reshareable components. (/ui was also supposed to be for wrappers that weren't included in chakra-ui but that we hadn't customized, but we haven't been enforcing that too well)

// Global setting: applies to all Dags (intentionally not scoped to dagId)
const [showVersionIndicatorMode, setShowVersionIndicatorMode] =
useLocalStorage<VersionIndicatorDisplayOptions>(
`version_indicator_display_mode`,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if we should make a src/constants/localStorage.ts file to keep track of how many localStorage values we have.

*/
import { createListCollection } from "@chakra-ui/react";

export enum VersionIndicatorDisplayOptions {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

VersionIndicatorOptions or VersionDisplayOptions

We use this a lot. Let's try to have a simpler variable name.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:API Airflow's REST/HTTP API area:UI Related to UI/UX. For Frontend Developers. type:new-feature Changelog: New Features

Projects

None yet

Development

Successfully merging this pull request may close these issues.

UI - Grid indicator for version change

9 participants

Comments